#include <stl/set.h>
#include <stl/vector.h>
#include <standard/geometrymath.h>
#include <standard/notification.h>
#include "helper/terrainactiveblockhelperobject.h"
#include "editorscenemgr.h"
#include "scene/editorscene.h"
#include "scene/sceneobjectnavigationmap.h"
#include "terrain/terrainblock.h"
#include "terrain/terrainobject.h"
#include "terrain/terraintexturelist.h"
#include "ui/navigationmappanel.h"
#include "command/navigationeditcmd.h"
#include "command/commandmgr.h"
#include "navigationmapeditoperator.h"
#include "global.h"


CNavigationMapEditOperator::CNavigationMapEditOperator( CEditorSceneMgr* pSceneMgr ):
COperator( pSceneMgr ) {
    m_eOperatorType = EOT_NAVIGATIONMAP_EDIT;
    m_bIsButtonDown = False;
    m_nButtonDownX = 0;
    m_nButtonDownY = 0;

    m_nButtonWorkX = 0;
    m_nButtonWorkY = 0;
}
CNavigationMapEditOperator::~CNavigationMapEditOperator(){

}
bool32 CNavigationMapEditOperator::Init(){
    int32 _nBrushType = CNavigationMapPanel::GetInterface()->GetSelectTerrainBrushType();
    int32 _nBrushSize = CNavigationMapPanel::GetInterface()->GetSelectTerrainBrushSize();
    m_rTerrainActiveBlockHelperObject = NEW CTerrainActiveBlockHelperObject();
    m_rTerrainActiveBlockHelperObject->Init( m_pSceneMgr->GetTerrainObject(), _nBrushType, _nBrushSize);
    m_pSceneMgr->GetScene()->AddChild(m_rTerrainActiveBlockHelperObject.GetEntityData());
    m_pSceneMgr->SetSceneVisibleMode( 1 );
    NOTIFICATION_REGISTER(SETTERRAINBRUSHTYPENOTIFICATION, 0, this, CNavigationMapEditOperator::OnNotification_SetTerrainBrushType);
    return True;
}
bool32 CNavigationMapEditOperator::Final(){
    m_pSceneMgr->GetScene()->RemoveChild(m_rTerrainActiveBlockHelperObject.GetEntityData());
    m_rTerrainActiveBlockHelperObject.Detach();
    NOTIFICATION_REMOVE_DELEGATE(SETTERRAINBRUSHTYPENOTIFICATION, this, CNavigationMapEditOperator::OnNotification_SetTerrainBrushType);
    return True;
}
bool32 CNavigationMapEditOperator::OnLMouseDown( int32 x, int32 y ){
    m_vNavigationDataInfoList.clear();
    m_bIsButtonDown = False;
    int32 _nDataIndex = CNavigationMapPanel::GetInterface()->GetSelectNavigationDataType();
    if( _nDataIndex == NAVIGATIONINFOCOUNT ){
        return False;
    }

    STerrainSelectedPosInfo _sTerrainSelectedPosInfo;
    CTerrainBlock* _pTerrainBlock = m_pSceneMgr->GetSelectBlock(x, y, &_sTerrainSelectedPosInfo );
    if (_pTerrainBlock) {
        SSETSTATUSCOORDTEXT _sSETSTATUSCOORDTEXT;
        _sSETSTATUSCOORDTEXT.m_fPosX = _sTerrainSelectedPosInfo.m_vPos[0];
        _sSETSTATUSCOORDTEXT.m_fPosY = _sTerrainSelectedPosInfo.m_vPos[1];
        _sSETSTATUSCOORDTEXT.m_fPosZ = _sTerrainSelectedPosInfo.m_vPos[2];
        _sSETSTATUSCOORDTEXT.m_nCellX = _sTerrainSelectedPosInfo.m_nCellX;
        _sSETSTATUSCOORDTEXT.m_nCellY = _sTerrainSelectedPosInfo.m_nCellY;
        NOTIFICATION_SEND(SETSTATUSCOORDTEXT, 0, 0, &_sSETSTATUSCOORDTEXT);

        //int32 _nBrushSize = CNavigationMapPanel::GetInterface()->GetSelectTerrainBrushSize();
        //int32 _nBrushType = CNavigationMapPanel::GetInterface()->GetSelectTerrainBrushType();
        m_bIsButtonDown = True;
        m_nButtonWorkX = x;
        m_nButtonWorkY = y;
        m_nButtonDownX = x;
        m_nButtonDownY = y;
        return True;
    }
    return False;
}
bool32 CNavigationMapEditOperator::OnMouseMove( int32 x, int32 y ){
    STerrainSelectedPosInfo _sTerrainSelectedPosInfo;
    CTerrainBlock* _pTerrainBlock = m_pSceneMgr->GetSelectBlock(x, y, &_sTerrainSelectedPosInfo );
    if (_pTerrainBlock) {
        SSETSTATUSCOORDTEXT _sSETSTATUSCOORDTEXT;
        _sSETSTATUSCOORDTEXT.m_fPosX = _sTerrainSelectedPosInfo.m_vPos[0];
        _sSETSTATUSCOORDTEXT.m_fPosY = _sTerrainSelectedPosInfo.m_vPos[1];
        _sSETSTATUSCOORDTEXT.m_fPosZ = _sTerrainSelectedPosInfo.m_vPos[2];
        _sSETSTATUSCOORDTEXT.m_nCellX = _sTerrainSelectedPosInfo.m_nCellX;
        _sSETSTATUSCOORDTEXT.m_nCellY = _sTerrainSelectedPosInfo.m_nCellY;
        NOTIFICATION_SEND(SETSTATUSCOORDTEXT, 0, 0, &_sSETSTATUSCOORDTEXT );
        
        int32 _nBrushSize = CNavigationMapPanel::GetInterface()->GetSelectTerrainBrushSize();
        list<CTerrainBlock*>* _pvTerrainBlockList = m_rTerrainActiveBlockHelperObject->UpdateActiveBlock( _sTerrainSelectedPosInfo.m_nCellX, _sTerrainSelectedPosInfo.m_nCellY, _nBrushSize );
        if (m_bIsButtonDown) {
            if (m_nButtonWorkX != x || m_nButtonWorkY != y) {
                _Work( _sTerrainSelectedPosInfo.m_vPos[0], _sTerrainSelectedPosInfo.m_vPos[2] );
                m_nButtonWorkX = x;
                m_nButtonWorkY = y;
                return True;
            }
        }
    }
    return False;
}
bool32 CNavigationMapEditOperator::OnLMouseUp( int32 x, int32 y ){
    bool32 _bResult = False;
    if (m_bIsButtonDown) {
        if (m_nButtonDownX == x || m_nButtonDownY == y) {
            STerrainSelectedPosInfo _sTerrainSelectedPosInfo;
            CTerrainBlock* _pTerrainBlock = m_pSceneMgr->GetSelectBlock(x, y, &_sTerrainSelectedPosInfo);
            if (_pTerrainBlock) {
                int32 _nBrushSize = CNavigationMapPanel::GetInterface()->GetSelectTerrainBrushSize();
                _Work(_sTerrainSelectedPosInfo.m_vPos[0], _sTerrainSelectedPosInfo.m_vPos[2]);
                _bResult = True;
            }
        }
        _FinishedWork();
    }
    m_bIsButtonDown = False;
    m_nButtonDownX = 0;
    m_nButtonDownY = 0;

    m_nButtonWorkX = 0;
    m_nButtonWorkY = 0;
    return _bResult;
}
void CNavigationMapEditOperator::_Work( float fPosX, float fPosY ){

    CSceneObjectNavigationMap* _pSceneObjectNavigationMap = m_pSceneMgr->GetSceneObjectNavigationMap();
    int32 _nBrushType = CNavigationMapPanel::GetInterface()->GetSelectTerrainBrushType();
    int32 _nBrushSize = CNavigationMapPanel::GetInterface()->GetSelectTerrainBrushSize();
    int32 _nDataIndex = CNavigationMapPanel::GetInterface()->GetSelectNavigationDataType();
    int32 _nValue = CNavigationMapPanel::GetInterface()->GetEditData();
    color32 _cValueColor = CNavigationMapPanel::GetInterface()->GetEditColor();
    

    int32 _nHalfBrushSize = _nBrushSize / 2;
    int32 _nCellX, _nCellY;
    if( _pSceneObjectNavigationMap->WorldToCellCoords( fPosX, fPosY, &_nCellX, &_nCellY ) ){
        for (int32 j = _nCellY - _nHalfBrushSize; j <= _nCellY + _nHalfBrushSize; j++) {
            for (int32 i = _nCellX - _nHalfBrushSize; i <= _nCellX + _nHalfBrushSize; i++) {
                if(i < 0 || j < 0 || i >= _pSceneObjectNavigationMap->m_nNavigCellSizeX || j >= _pSceneObjectNavigationMap->m_nNavigCellSizeY )
                    continue;
                SNavigationLayerDataInfo* _pNavigationDataInfo = _pSceneObjectNavigationMap->GetInfoItem( i, j );
                if( _pNavigationDataInfo[ _nDataIndex ].m_nValue != _nValue || _pNavigationDataInfo[ _nDataIndex ].m_cColor != _cValueColor ){
                    uint32 _nKey = MAKELONG( i, j );
                    map< uint32, SNavigationDataInfo >::iterator it = m_vNavigationDataInfoList.find( _nKey );
                    if( it == m_vNavigationDataInfoList.end()){
                        SNavigationDataInfo _sNavigationDataInfo;
                        _sNavigationDataInfo.m_nX = i;
                        _sNavigationDataInfo.m_nY = j;
                        _sNavigationDataInfo.m_nOldDataInfo = _pNavigationDataInfo[ _nDataIndex ].m_nValue;
                        _sNavigationDataInfo.m_nNewDataInfo = _nValue;
                        _sNavigationDataInfo.m_cOldDataColor = _pNavigationDataInfo[ _nDataIndex ].m_cColor;
                        _sNavigationDataInfo.m_cNewDataColor = _cValueColor;
                        m_vNavigationDataInfoList.insert( _nKey, _sNavigationDataInfo );
                    }else{
                        SNavigationDataInfo* _pNavigationDataInfo = &(it.second());
                        _pNavigationDataInfo->m_nNewDataInfo = _nValue;
                        _pNavigationDataInfo->m_cNewDataColor = _cValueColor;
                    }
                    _pNavigationDataInfo[ _nDataIndex ].m_nValue = _nValue;
                    _pNavigationDataInfo[ _nDataIndex ].m_cColor = _cValueColor;
                }
            }
        }
    }

    if( m_vNavigationDataInfoList.size() > 0 ){
        _pSceneObjectNavigationMap->UpdateTextureData();
    }
}
void CNavigationMapEditOperator::OnNotification_SetTerrainBrushType( int32 w, int32 l, void* pUserData ){
    m_rTerrainActiveBlockHelperObject->SetBrushInfo(w, l);
}
void CNavigationMapEditOperator::_FinishedWork(){
    int32 _nDataIndex = CNavigationMapPanel::GetInterface()->GetSelectNavigationDataType();
    if( m_vNavigationDataInfoList.size() > 0 ){
        list< SNavigationDataInfo > _vNavigationDataInfoList;
        map< uint32, SNavigationDataInfo >::iterator it = m_vNavigationDataInfoList.begin();
        map< uint32, SNavigationDataInfo >::iterator it_end = m_vNavigationDataInfoList.end();
        for( ; it != it_end; it ++ ){
            _vNavigationDataInfoList.push_back( it.second() );
        }
        CNavigationEditCmd* _pTerrainSurfaceEditCmd = NEW CNavigationEditCmd( _nDataIndex, &_vNavigationDataInfoList );
        m_pSceneMgr->GetCommandMgr()->AddCommand( _pTerrainSurfaceEditCmd );
        m_vNavigationDataInfoList.clear();
    }
}


